# OOP

# 类定义
class Bird:
    song = "Squaak."

    def sing(self):
        print(self.song)


#
bird = Bird()
bird.sing()  # Squaak.

# 使用函数指向实例的方法
birdsong = bird.sing
birdsong()  # Squaak.


# 私有属性

class Secretive:
    """
    私有方法 _methodName 可以外部调用不推荐
    私有方法 __methodName 不能外部调用
    """

    def __inaccessible(self):
        print("私有方法")

    def accessible(self):
        print("公开方法")
        self.__inaccessible()


s = Secretive()
s.accessible()
# s.__inaccessible()  # 调用不了

# 通过特殊的路径可以调用到，python不能完全禁止外部调用私有方法，只能君子约定
# _类名__私有方法
s._Secretive__inaccessible()  # 私有方法


#
class MemberCounter:
    # 类变量
    members = 0

    def init(self):
        MemberCounter.members += 1


m1 = MemberCounter()
m1.init()

m2 = MemberCounter()
m2.init()

print(m1.members, m2.members)  # 2 2


# 超类

class Filter:
    def init(self):
        self.blocked = []

    def filter(self, sequence):
        return [x for x in sequence if x not in self.blocked]


class SPAMFilter(Filter):  # SPAMFilter是Filter的子类
    def init(self):  # 重写超类Filter的方法init
        self.blocked = ['SPAM']


f = Filter()
f.init()
print(f.filter([1, 2, 3]))  # [1, 2, 3]

#
s = SPAMFilter()
s.init()
print(s.filter(['SPAM', 'SPAM', 'SPAM', 'SPAM', 'eggs', 'bacon', 'SPAM']))  # ['eggs', 'bacon']


# 类继承关系判定 issubclass
class Parent:
    pass


class Child(Parent):
    pass


print(issubclass(Child, Parent))  # 返回True，因为Child是Parent的子类
print(issubclass(Parent, Child))  # 返回False，因为Parent不是Child的子类

# 获取一个类的基类
print(Child.__bases__)  # (<class '__main__.Parent'>,)

# 判定一个对象是不是一个类
c1 = Child()
p1 = Parent()
print(f"isinstance(c1, Child)={isinstance(c1, Child)}")  # isinstance(c1, Child)=True
print(f"isinstance(c1, Parent)={isinstance(c1, Parent)}")  # isinstance(c1, Parent)=True
print(f"isinstance(p1, Parent)={isinstance(p1, Parent)}")  # isinstance(p1, Parent)=True
print(f"isinstance(p1, Child)={isinstance(p1, Child)}")  # isinstance(p1, Child)=False

# 获取一个对象的类

print(c1.__class__)  # <class '__main__.Child'>
print(p1.__class__)  # <class '__main__.Parent'>


# 多个超类
class Calculator:
    def calculate(self, expression):
        self.value = eval(expression)


class Talker:
    def talk(self):
        print('Hi, my value is', self.value)


class TalkingCalculator(Calculator, Talker):
    pass


print(TalkingCalculator.__bases__)  # (<class '__main__.Calculator'>, <class '__main__.Talker'>)
#
tc = TalkingCalculator()
tc.calculate('1+2*3')
tc.talk()  # Hi, my value is 7

# 接口或者方法检查 hasattr
print(hasattr(tc, 'talk'))  # True
print(hasattr(tc, 'talkxx'))  # False

# 获取方法并调用
talkMethod = getattr(tc, 'talk')
print(talkMethod)  # <bound method Talker.talk of <__main__.TalkingCalculator object at 0x000001F2D7C68C10>>

# 是否可以调用
print(callable(talkMethod))  # True

# 设置属性
setattr(tc, 'name', 'MM')
print(tc.name)  # MM

# 查看对象的所有属性
print(tc.__dict__)  # {'value': 7, 'name': 'MM'}

# abc
from abc import ABC, abstractmethod


# 定义接口 和抽象方法
class Talker(ABC):
    @abstractmethod
    def talk(self):
        pass


# Talker() #TypeError: Can't instantiate abstract class Talker with abstract method talk

# 没有实现抽象方法，也是不能实例化的
class Knigget(Talker):
    pass


# Knigget()  # TypeError: Can't instantiate abstract class Knigget with abstract method talk
#
class KniggetImpl(Talker):
    def talk(self):
        print("KniggetImpl")


# 实例化并调用方法
KniggetImpl().talk()  # KniggetImpl


# 没有实现Talker方法，但是实现了talk方法
class Herring:
    def talk(self):
        print("Herring")


h = Herring()
print(isinstance(h, Talker))  # False

# 将Herring注册成为Talker的实现类
Talker.register(Herring)
print(isinstance(h, Talker))  # True
print(issubclass(Herring, Talker))  # True

# 获取对象的类型
print(type(h))  # <class '__main__.Herring'>
